package contegor.scire.core;


/**
 * <code>{@link Link}</code> implementation.
 * 
 * @version $Revision: 1.7 $
 * @author  Héctor Cirbián Pousa ($Author: hector $)
 */
@Version("$Id: LinkImpl.java,v 1.7 2010-02-01 10:55:39 hector Exp $")
public class LinkImpl extends ConnectableImpl implements Link, Cloneable, Comparable<LinkImpl> {
  private static final long serialVersionUID = 2310445721940166218L;

  private Connectable source;
  private Id          target;
  private Flow        flow;

  /** Package private constructor so this object can't be instantiated outside it. */
  protected LinkImpl(long creationTime, TransactionId transactionId, Flow flow) {
    super(creationTime, transactionId);
    this.source = null;
    this.target = null;
    this.flow   = flow;
  }  

  public Connectable getSource() {
    return source;
  }

  @Override
  public Concept getFinalSourceConcept() {
    Connectable aux = this.getSource();
    while (aux instanceof Link)
      aux = ((Link)aux).getSource();
    return (Concept)aux;
  }

  public Id getTarget() {
    return target;
  }

  public Flow getFlow() {
    return flow;
  }

  /* (non-Javadoc)
   * @see contegor.scire.core.ConnectableImpl#equals(java.lang.Object)
   */
  @Override
  public boolean equals(Object rhs) {
    if (!super.equals(rhs))
      return false;
    if (!(rhs instanceof Link))
      return false;
    Link obj = (Link)rhs;
    if (!target.equals(obj.getTarget()))
      return false;
    return source.equals(obj.getSource());
  }

  @Override
  public int hashCode() {
    int res = target.hashCode();
    if (source instanceof Identifiable)
      res *= ((Identifiable)source).hashCode();
    return res;
  }

  public LinkImpl clone() throws CloneNotSupportedException {
    LinkImpl lhs = (LinkImpl)super.clone();
    // The source must be cloned before the link, so clone it again is an error: lhs.source   = ((ConnectableImpl)this.source).clone();
    // Id is immutable, so there is no need to clone 'target'.
    return lhs;
  }
  
  protected LinkImpl clone(Connectable source) throws CloneNotSupportedException {
    LinkImpl lhs = (LinkImpl)super.clone();
    lhs.source   = source;
    // Id is immutable, so there is no need to clone 'target'.
    return lhs;
  }

  protected void setSource(Connectable source) {
    this.source = source;
  }

  protected void setTarget(Id target) {
    this.target = target;
  }

  @Override
  public int compareTo(LinkImpl rhs) {
    int comp = this.getTarget().compareTo(rhs.getTarget());
    if (comp != 0)
      return comp;
    Connectable source1 = this.getSource();
    Connectable source2 = rhs.getSource();
    if ((source1 instanceof Identifiable) && (source2 instanceof Identifiable))
      return ((Identifiable)source1).getId().compareTo(((Identifiable)source2).getId());
    if ((source1 instanceof LinkImpl) && (source2 instanceof LinkImpl))
      return ((LinkImpl)source1).compareTo((LinkImpl)source2);
    if (source1 instanceof Identifiable)
      return 1;
    else
      return -1;
  }

  @Override
  public String toString() {
    return "LinkImpl [flow=" + flow + ", source=" + (source instanceof Identifiable ? ((Identifiable)source).getId() : "link") + ", target=" + target + "] " + super.toString();
  }
}